/**
 * Copyright (C) 2009+ Spark Zheng
 *
 * @file        src/filt_types.h 
 * @date        2010-04-27
 * @brief	general_datastream
 * @see         dserver
 * @history
 */

#ifndef _DSERVER_FILT_TYPES_H
#define _DSERVER_FILT_TYPES_H

#ifdef __cplusplus
extern "C" {
#endif

#include <dlib/global.h>
#include <dlib/list.h>
#include <dlib/mempool.h>
#include <dlib/threadpool.h>

typedef struct filter_setting	filter_setting_t;
typedef struct filter_ops	filter_ops_t;
typedef struct filter_node	filter_node_t;

typedef struct pipeline_node	pipeline_node_t;
typedef struct pipeline_data	pipeline_data_t;

/** filter struct */
struct filter_setting {
	uint16_t	f_pmin;		/** filter tpool min thread_nr */
	uint16_t	f_pmax;		/** filter tpool max thread_nr */
	uint16_t	f_timeout;	/** filter default timeout */
	uint16_t	f_priority;	/** filter default priority */
	uint16_t	f_pipeline_id;	/** filter pipeline id */
	uint16_t	f_filter_id;	/** filter id */
};

/**
 * important structure in filters
 * -f_filter_load:
 * -f_stream_init:
 * -f_stream_worker:
 * -f_stream_timeout:
 * -f_stream_finish:
 * -f_stream_exit:
 * -f_filter_unload:
 */
struct filter_ops {
#define FILTER_LOAD_STR		"filter_on_load"
#define STREAM_INIT_STR		"filter_stream_init"
#define STREAM_WORKER_STR	"filter_stream_worker"
#define STREAM_FINISH_STR	"filter_stream_finish"
#define STREAM_TIMEOUT_STR	"filter_stream_timeout"
#define STREAM_EXIT_STR		"filter_stream_exit"
#define FILTER_UNLOAD_STR	"filter_on_unload"
	int	(*f_filter_load)(const void *, filter_node_t *);
	void*	(*f_stream_init)(void *);
	void*	(*f_stream_worker)(void *, void *);
	void*	(*f_stream_timeout)(void *, void *);
	void*	(*f_stream_finish)(void *, void *);
	void	(*f_stream_exit)(void *);
	void	(*f_filter_unload)(filter_node_t *);
};

struct filter_node {
	char			*f_name;	/** filter uniq name */
	
	filter_setting_t	f_settings;	/** filter settings */
	filter_ops_t		f_ops;		/** filter callback functions */
	void			*f_handler;	/** filter lib.so handler */

	dlib_tpool_t		*f_tpool;	/** tpool structure, used in pipeline */
	
	list_node_t		f_node;		/** filter list_node */
	list_node_t		p_node;		/** pipeline list_node */
	
	void			*f_data;	/** filter other data in privacy */
};

/** pipeline node struct */
struct pipeline_node {
	uint16_t	p_filter_nr;	/** number of filter */
	list_head_t	p_filter_head;	/** pipeline filters list */
};

/** pipeline_data prot_flag */
typedef enum {
	PROT_PIPELINE_NOTSET = 0,
	PROT_PIPELINE_BEGIN = 1,	/** pipeline begin */
	PROT_PIPELINE_IGNORE,		/** protocol return ignore */
	PROT_PIPELINE_STOP,		/** not used yet */
	PROT_PIPELINE_CONTINUE,		/** not used yet */
	PROT_PIPELINE_END		/** pipeline end */
} pipeline_stat_t;

/** pipeline_data filter_flag */
typedef enum {
	FILT_PIPELINE_NOTSET = 0,
	FILT_PIPELINE_SUCCESS = 1,	/** filter execute success */
	FILT_PIPELINE_TIMEOUT,		/** filter execute timeout */
	FILT_PIPELINE_ERROR		/** filter execute error */
} filter_stat_t;

/**
 * pipeline_data_t
 * @brief the data struct passed between two filters
 */
struct pipeline_data {
	pipeline_stat_t	p_prot_flag;		/** protocol flag */
	filter_stat_t	p_filter_flag;		/** filter flag */

	filter_node_t	*p_submit_fnode;	/** fnode submit by */
	pipeline_node_t	*p_submit_pnode;	/** pnode submit by */

	pthread_mutex_t	p_mutex;		/** condition mutex */
	pthread_cond_t	p_cond;			/** timed condition */

	void		*p_data;		/** the relay data pointer */
};


/** filter common APIs */
static inline void pipeline_data_setup(pipeline_data_t *pdata)
{
	pdata->p_prot_flag = PROT_PIPELINE_BEGIN;
	pdata->p_filter_flag = FILT_PIPELINE_NOTSET;
	pthread_mutex_init(&pdata->p_mutex, NULL);
	pthread_cond_init(&pdata->p_cond, NULL);
	pdata->p_submit_fnode = NULL;
	pdata->p_submit_pnode = NULL;
	return;
}

static inline void pipeline_data_cleanup(pipeline_data_t *pdata)
{
	pthread_cond_destroy(&pdata->p_cond);
	pthread_mutex_destroy(&pdata->p_mutex);
	pdata->p_prot_flag = PROT_PIPELINE_NOTSET;
	pdata->p_filter_flag = FILT_PIPELINE_NOTSET;
	return;
}

static inline pipeline_data_t *pipeline_data_init(void)
{
	pipeline_data_t *pdata = NULL;
	if ((pdata = (pipeline_data_t *)dmalloc_nb(sizeof(*pdata))) == NULL) {
		return NULL;
	} else {
		pipeline_data_setup(pdata);
	}
	return pdata;
}

static inline void pipeline_data_exit(pipeline_data_t *pdata)
{
	if (pdata == NULL)
		return;
	pipeline_data_cleanup(pdata);
	dfree(pdata);
	pdata = NULL;
	return;
}

/**
 * filter_get_ids_by_name
 * @brief get filter_id and pipeline_id for a filter by its name
 * @return < 0 means error
 * @param name: filter name
 * @param fid[out]: filter_id
 * @param pid[out]: pipeline_id
 */
extern int filter_get_ids_by_name(const char *name, uint16_t *fid, uint16_t *pid);

/**
 * filter_get_name_by_fid
 * @brief get filter name by its filter_id
 * @return NULL means not exist or error
 * @param fid[in]: filter_id
 */
extern char *filter_get_name_by_fid(uint16_t fid);

/**
 * filter_get_by_fid
 * @brief get the filter by its filter_id
 * @return NULL means not exist or error
 * @param fid[in]: filter_id
 */
extern filter_node_t *filter_get_by_fid(uint16_t fid);

/**
 * pipeline_get_by_fid
 * @brief get the pipeline which the filter is in by filter's id
 * @return NULL means not exist or error
 * @param fid[in]: filter_id
 */
extern pipeline_node_t *pipeline_get_by_fid(uint16_t fid);

/**
 * filter_get_by_name
 * @brief get the filter by its name
 * @return NULL means not exist or error
 * @param name: filter name
 */
extern filter_node_t *filter_get_by_name(const char *name);

/**
 * pipeline_get_by_name
 * @brief get the pipeline which the filter is in by filter's name
 * @return NULL means not exist or error
 * @param name: filter name
 */
extern pipeline_node_t *pipeline_get_by_name(const char *name);

/**
 * pipeline_dispatch
 * @brief do pipeline flow, deliver data to pnode-fnode and receive data from pnode-fnode
 *	  called in main thread
 * @return < 0 means error
 * @param pnode: the pipeline node
 * @param fnode[in]: the begin filter node
 * @param pdata[in]: handlering pdata
 */
extern int pipeline_dispatch(pipeline_node_t *pnode, filter_node_t *fnode,
		pipeline_data_t *pdata);

/**
 * pipeline_request
 * @brief pipeline begin, deliver data to pnode-fnode
 *	  called in main thread
 * @return < 0 means error
 * @param pnode: the pipeline node
 * @param fnode[in]: the begin filter node
 * @param pdata[in]: handlering pdata
 */
extern int pipeline_request(pipeline_node_t *pnode, filter_node_t *fnode,
		pipeline_data_t *pdata);

/**
 * pipeline_deliver_next
 * @brief pipeline continue, deliver handlered-data to next fnode in same pnode
 *	  called in filter-worker thread
 * @return < 0 means error
 * @param fnode[in]: the current-filter node
 * @param pdata[in]: handlered-pdata
 */
extern int pipeline_deliver_next(filter_node_t *fnode, pipeline_data_t *pdata);

/**
 * pipeline_deliver
 * @brief pipeline continue, deliver handlered-data to another pnode-fnode
 *	  called in filter-worker thread
 * @return < 0 means error
 * @param fnode[in]: the dist-filter node
 * @param pdata[in]: handlered-pdata
 */
extern int pipeline_deliver(filter_node_t *fnode, pipeline_data_t *pdata);

/**
 * pipeline_submit
 * @brief pipeline end, deliver handlered-data from pnode to main thread
 *	  called in filter-worker thread, SYNC model
 * @return < 0 means error
 * @param fnode[in]: the end filter node
 * @param pdata[in]: handlered-pdata
 */
extern int pipeline_submit(filter_node_t *fnode, pipeline_data_t *pdata);

/**
 * pipeline_submit_async
 * @brief pipeline end, deliver handlered-data from pnode to main thread
 *	  called in special thread, ASYNC model
 * @return < 0 means error
 * @param fnode[in]: the end filter node
 * @param pdata[in]: handlered-pdata
 */
extern int pipeline_submit_async(filter_node_t *fnode, pipeline_data_t *pdata);

/**
 * pipeline_result
 * @brief pipeline end, receive handlered-data from pnode-fnode
 *	  called in main thread
 * @return < 0 means error
 * @param pdata[in]: handlered-pdata
 */
extern int pipeline_result(pipeline_data_t *pdata);


#ifdef __cplusplus
}
#endif
#endif
